// Transform1.cs created with MonoDevelop
// User: werner at 20:10 9-1-2009
//
// To change standard headers go to Edit->Preferences->Coding->Standard Headers
//

using System;
using System.IO;
using System.Collections.Generic;

namespace AdvancedProgramming
{
		
	public class Transform1
	{
        private int editCounter = 0;
        private int costCounter = 0;

        public int CostCounter
        {
            get { return costCounter; }
            set { costCounter = value; }
        }

        public int EditCounter
        {
            get { return editCounter; }
            set { editCounter = value; }
        }
        
		public Transform1()
		{
			
		}

        public List<string> Compare(string filename1, string filename2)
        {
            List<string> file1 = FileLoader.LoadFile(filename1);
            List<string> file2 = FileLoader.LoadFile(filename2);
            return Edit(file1, file2);
        }

		private List<string> Edit(List<string> string1, List<string> string2)
		{
            editCounter++;
			List<string> editActions = new List<string>();

            if (string1.Count ==0 && string2.Count == 0) // beide strings leeg, geen actie
            {

            }
            else if (string1.Count == 0) // string1 leeg, Insert One actie
            {
                foreach (string str in string2)
                {
                    editActions.Add(Constants.INSERT_ONE + ": " + str);
                }
            }
            else if (string2.Count == 0) // string 2 leeg, Delete One actie
            {
                editActions.Add(Constants.DELETE_END);
            }
            else if (string1.Equals(string2)) // string1 en string2 zijn gelijk, Copy One actie
            {
                editActions.Add(Constants.COPY_ONE);
                string1.RemoveAt(0); // verwijder verwerkte regel
                string2.RemoveAt(0); // verwijder verwerkte regel
                editActions.AddRange(Edit(new List<string>(string1), new List<string>(string2)));
            }
            else
            {
                int costDelOne, costInsertOne, costChangeOne = 0;

                List<string> cpyString1 = new List<string>(string1);
                List<string> cpyString2 = new List<string>(string2);

                cpyString1.RemoveAt(0);

                if (cpyString1.Count != 0)
                {
                    costDelOne = EditDistance.Distance(cpyString1[0], string2[0]);
                    costInsertOne = EditDistance.Distance(string1[0], cpyString2[0]);
                    costChangeOne = EditDistance.Distance(cpyString1[0], cpyString2[0]);
                    costCounter = costDelOne + costInsertOne + costChangeOne;

                    if (costDelOne < costInsertOne)
                    {
                        if (costDelOne < costChangeOne)
                        {
                            editActions.Add(Constants.DELETE_ONE);
                        }
                        else
                        {
                            editActions.Add(Constants.CHANGE_ONE + ": " + string2[0]);
                        }
                        editActions.AddRange(Edit(new List<string>(cpyString1), new List<string>(cpyString2)));
                    }
                    else
                    {
                        if (costInsertOne < costChangeOne)
                        {
                            editActions.Add(Constants.INSERT_ONE + ": " + string2[0]);
                        }
                        else
                        {
                            editActions.Add(Constants.CHANGE_ONE + ": " + string2[0]);
                        }
                        editActions.AddRange(Edit(new List<string>(cpyString1), new List<string>(cpyString2)));
                    }
                }
            }
			
			return editActions;
		}

        private class EditDistance
        {
            private int costCounter = 0;

            public int CostCounter
            {
                get { return costCounter; }
                set { costCounter = value; }
            }

            private int[] cost;
            private int[] back;
            private string a, b;

            public EditDistance(string a, string b)
            {
                this.a = a;
                this.b = b;
                cost = new int[a.Length+1];
                back = new int[b.Length+1];
                for (int i = 0; i <= a.Length; i++)
                    cost[i] = i;
            }

            public static int Distance(string string1, string string2)
            {
                EditDistance ed = new EditDistance(string1, string2);
                return ed.Calculate();
            }

            public static string FindNearest(string str, string[] grp)
            {
                List<string> lst = new List<string>(grp);
                return FindNearest(str, lst);
            }

            public static string FindNearest(string str, List<string> grp)
            {
                int c = Int32.MaxValue;
                string r = null;

                foreach (string g in grp)
                {
                    int ed = Distance(str, g);
                    if (c > ed)
                    {
                        c = ed;
                        r = g;
                    }
                }
                return r;
            }

            private void flip()
            {
                int[] t = cost;
                cost = back;
                back = t;
            }

            private int min(int a, int b, int c)
            {
                return Math.Min(a, Math.Min(b, c));
            }

            private int Calculate()
            {
                for (int j = 0; j < b.Length; j++)
                {
                    flip();
                    cost[0] = j+1;
                    for (int i = 0; i < a.Length; i++)
                    {
                        int match = (a[i] == b[j]) ? 0 : 1;
                        cost[i] = min(back[i] + match, cost[i]++, back[i]++);
                    }
                }
                return cost.Length;
            }



        }

				
	}
}
